/*
   (c) Copyright 2012-2013  DirectFB integrated media GmbH
   (c) Copyright 2001-2013  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Shimokawa <andi@directfb.org>,
              Marek Pikarski <mass@directfb.org>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/



#include <config.h>

#include <core/CoreWindow.h>

extern "C" {
#include <directfb_util.h>

#include <direct/debug.h>
#include <direct/mem.h>
#include <direct/messages.h>

#include <core/windows.h>
#include <core/windowstack.h>
#include <core/wm.h>
}

D_DEBUG_DOMAIN( Core_Window, "Core/Window", "DirectFB Core Window" );

/*********************************************************************************************************************/

namespace DirectFB {


DFBResult
IWindow_Real::Repaint( const DFBRegion     *left,
                       const DFBRegion     *right,
                       DFBSurfaceFlipFlags  flags,
                       s64                  timestamp )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p, timestamp %lld )\n", __FUNCTION__, obj, (long long) timestamp );

     D_MAGIC_ASSERT( obj, CoreWindow );
     D_ASSERT( left != NULL );
     D_ASSERT( right != NULL );

     return dfb_window_repaint( obj, left, right, flags, timestamp );
}

DFBResult
IWindow_Real::Restack( CoreWindow *relative,
                       int         relation )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     DFBResult        ret;
     CoreWindowStack *stack;

     D_MAGIC_ASSERT( obj, CoreWindow );
     D_ASSERT( obj->stack != NULL );

     stack = obj->stack;

     /* Lock the window stack. */
     if (dfb_windowstack_lock( stack ))
          return DFB_FUSION;

     /* Never call WM after destroying the window. */
     if (DFB_WINDOW_DESTROYED( obj )) {
          dfb_windowstack_unlock( stack );
          return DFB_DESTROYED;
     }

     /* Let the window manager do its work. */
     ret = dfb_wm_restack_window( obj, relative, relation );

     /* Unlock the window stack. */
     dfb_windowstack_unlock( stack );

     return ret;
}

DFBResult
IWindow_Real::SetConfig( const CoreWindowConfig        *config,
                         const DFBInputDeviceKeySymbol *keys,
                         u32                            num_keys,
                         CoreWindowConfigFlags          flags )
{
     CoreWindowConfig config_copy;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );
     D_ASSERT( config != NULL );

     if ((flags & DWCONF_ASSOCIATION) && config->association) {
          DFBResult ret;
          CoreWindow *parent;

          ret = dfb_core_get_window( core, config->association, &parent );
          if (ret)
               return ret;

          if (fusion_object_check_owner( &parent->object, Core_GetIdentity(), false )) {
               dfb_window_unref( parent );
               return DFB_ACCESSDENIED;
          }

          dfb_window_unref( parent );
     }

     config_copy = *config;

     config_copy.keys     = (DFBInputDeviceKeySymbol*) keys;
     config_copy.num_keys = num_keys;

     return dfb_window_set_config( obj, &config_copy, flags );
}

DFBResult
IWindow_Real::Bind( CoreWindow *source,
                    int         x,
                    int         y )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );
     D_MAGIC_ASSERT( source, CoreWindow );

     return dfb_window_bind( obj, source, x, y );
}

DFBResult
IWindow_Real::Unbind( CoreWindow *source )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );
     D_MAGIC_ASSERT( source, CoreWindow );

     return dfb_window_unbind( obj, source );
}

DFBResult
IWindow_Real::RequestFocus()
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_request_focus( obj );
}

DFBResult
IWindow_Real::ChangeGrab( CoreWMGrabTarget     target,
                          DFBBoolean           grab )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_change_grab( obj, target, grab );
}

DFBResult
IWindow_Real::GrabKey( DFBInputDeviceKeySymbol     symbol,
                       DFBInputDeviceModifierMask  modifiers )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_grab_key( obj, symbol, modifiers );
}

DFBResult
IWindow_Real::UngrabKey( DFBInputDeviceKeySymbol     symbol,
                         DFBInputDeviceModifierMask  modifiers )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_ungrab_key( obj, symbol, modifiers );
}

DFBResult
IWindow_Real::Move( int dx,
                    int dy )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_move( obj, dx, dy, true );
}

DFBResult
IWindow_Real::MoveTo( int x,
                      int y )
{
     DFBResult ret;
     DFBInsets insets;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     dfb_windowstack_lock( obj->stack );

     dfb_wm_get_insets( obj->stack, obj, &insets );

     ret = dfb_window_move( obj, x + insets.l, y + insets.t, false );

     dfb_windowstack_unlock( obj->stack );

     return ret;
}

DFBResult
IWindow_Real::Resize( int width,
                      int height )
{
     DFBResult ret;
     DFBInsets insets;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     dfb_windowstack_lock( obj->stack );

     dfb_wm_get_insets( obj->stack, obj, &insets );

     ret = dfb_window_resize( obj, width + insets.l+insets.r, height + insets.t+insets.b );

     dfb_windowstack_unlock( obj->stack );

     return ret;
}

DFBResult
IWindow_Real::Destroy()
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     dfb_window_destroy( obj );

     return DFB_OK;
}

DFBResult
IWindow_Real::BeginUpdates( const DFBRegion *update )
{
     DFBResult ret;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     dfb_windowstack_lock( obj->stack );

     ret = dfb_wm_begin_updates( obj, update );

     dfb_windowstack_unlock( obj->stack );

     return ret;
}

DFBResult
IWindow_Real::SetCursorPosition( int x,
                                 int y )
{
     DFBResult ret;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     dfb_windowstack_lock( obj->stack );

     ret = dfb_wm_set_cursor_position( obj, x, y );

     dfb_windowstack_unlock( obj->stack );

     return ret;
}

DFBResult
IWindow_Real::ChangeEvents( DFBWindowEventType disable,
                            DFBWindowEventType enable )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_change_events( obj, disable, enable );
}

DFBResult
IWindow_Real::ChangeOptions( DFBWindowOptions disable,
                             DFBWindowOptions enable )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_change_options( obj, disable, enable );
}

DFBResult
IWindow_Real::SetColor( const DFBColor *color )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_color( obj, *color );
}

DFBResult
IWindow_Real::SetColorKey( u32 key )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_colorkey( obj, key );
}

DFBResult
IWindow_Real::SetOpaque( const DFBRegion *opaque )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_opaque( obj, opaque );
}

DFBResult
IWindow_Real::SetOpacity( u8 opacity )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_opacity( obj, opacity );
}

DFBResult
IWindow_Real::SetStacking( DFBWindowStackingClass stacking )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_change_stacking( obj, stacking );
}

DFBResult
IWindow_Real::SetBounds( const DFBRectangle *bounds )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_bounds( obj, DFB_RECTANGLE_VALS( bounds ) );
}

DFBResult
IWindow_Real::SetKeySelection( DFBWindowKeySelection          selection,
                               const DFBInputDeviceKeySymbol *keys,
                               u32                            num_keys )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_key_selection( obj, selection, keys, num_keys );
}

DFBResult
IWindow_Real::SetRotation( int rotation )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_rotation( obj, rotation );
}

DFBResult
IWindow_Real::GetSurface(
                    CoreSurface                              **ret_surface
)
{
     DFBResult ret;

     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_ASSERT( ret_surface != NULL );

     if (!obj->surface)
          return DFB_UNSUPPORTED;

     ret = (DFBResult) dfb_surface_ref( obj->surface );
     if (ret)
          return ret;

     *ret_surface = obj->surface;

     return DFB_OK;
}

DFBResult
IWindow_Real::SetCursorShape(
                    CoreSurface                               *shape,
                    const DFBPoint                            *hotspot )
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     return dfb_window_set_cursor_shape( obj, shape, hotspot->x, hotspot->y );
}

DFBResult
IWindow_Real::AllowFocus()
{
     D_DEBUG_AT( Core_Window, "IWindow_Real::%s( %p )\n", __FUNCTION__, obj );

     D_MAGIC_ASSERT( obj, CoreWindow );

     /*
      * Remove DWCAPS_NOFOCUS, unless requested by the application itself.
      */
     obj->caps = (DFBWindowCapabilities)((obj->caps & ~DWCAPS_NOFOCUS) | (obj->requested_caps & DWCAPS_NOFOCUS));

     return DFB_OK;
}


DFBResult
IWindow_Real::GetInsets(
     DFBInsets                                *ret_insets
)
{
    DFBResult ret;

    D_DEBUG_AT( Core_Window, "IWindow_Real::%s()\n", __FUNCTION__ );

    ret = (DFBResult) dfb_layer_context_lock( obj->stack->context );
    if (ret)
         return ret;

    ret = dfb_wm_get_insets( obj->stack, obj, ret_insets );

    dfb_layer_context_unlock( obj->stack->context );

    return ret;
}

DFBResult
IWindow_Real::PostEvent(
     const DFBWindowEvent                    *event
)
{
    DFBWindowEvent e;

    D_DEBUG_AT( Core_Window, "IWindow_Real::%s()\n", __FUNCTION__ );

    e = *event;

    dfb_window_post_event( obj, &e );

    return DFB_OK;
}


}

